﻿using System;
using System.Collections.Generic;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Drawing;
using System.Windows.Forms;
using Microsoft.Xna.Framework;
using Color = System.Drawing.Color;

namespace TowerDef_s_enseEditor
{
    public class Map
    {
        #region variables

        string _currentTexture;
        public string CurrentTexture
        {
            set
            {
                _currentTexture = value;
            }
        }

        MapButton _button;

        /* 
         * MapButton.ImageNumber:
         * 0 - Start
         * 1 - Grass
         * 2 - Path
         * 3 - Goal
         * 4 - Conflict
         */

        Editor _editor;

        private List<MapButton> _buttonList;
        public List<MapButton> ButtonList
        {
            get
            {
                return _buttonList;
            }
        }

        #endregion

        #region functions

        /// <summary>
        /// Initializes the Map
        /// </summary>
        /// <param name="editor">The current form in which the map will be included</param>
        public void InitializeMap(Editor editor)
        {
            int i = 0;

            this._editor = editor;

            _buttonList = new List<MapButton>();

            for(int y = 0; y < 18; y++)
            {
                for(int x = 0; x < 18; x++)
                {
                    _button = new MapButton();
                    _button.ForeColor = System.Drawing.Color.Transparent;
                    _button.Image = Properties.Resources.grass_1;
                    _button.BackgroundImageLayout = System.Windows.Forms.ImageLayout.Stretch;
                    _button.FlatAppearance.BorderSize = 0;
                    _button.FlatStyle = System.Windows.Forms.FlatStyle.Popup;
                    _button.Location = new System.Drawing.Point(8 + x * 32, 26 + y * 32);
                    _button.Index = i++;
                    _button.ImageNumber = 1;
                    _button.PreviousImageIndex = 1;
                    _button.Size = new System.Drawing.Size(32, 32);
                    _button.UseVisualStyleBackColor = true;
                    _button.Click += new System.EventHandler(ButtonClick);

                    _buttonList.Add(_button);
                    this._editor.Controls.Add(_button);
                }
            }
        }

        /// <summary>
        /// Resets the map to grass only
        /// </summary>
        public void ClearMap()
        {
            for(int j = 0; j < _buttonList.Count; j++)
            {
                _buttonList.ElementAt(j).Enabled = true;
                _buttonList.ElementAt(j).Image = Properties.Resources.grass_1;
                _buttonList.ElementAt(j).ImageNumber = 1;
            }
        }

        /// <summary>
        /// Checks the setting of a start _button in the map
        /// </summary>
        /// <returns>True if start is set</returns>
        public bool StartIsset()
        {
            return _buttonList.Any(b => b.ImageNumber == 0);

            //Same like:
            //foreach (MapButton b in _buttonList)
            //{
            //    if (b.ImageNumber == 0)
            //        return true;
            //}
            //return false;
        }

        /// <summary>
        /// Checks the setting of a goal _button in the map
        /// </summary>
        /// <returns>True if goal is set</returns>
        public bool GoalIsset()
        {
            return _buttonList.Any(b => b.ImageNumber == 3);

            //Same like:
            //foreach (MapButton b in _buttonList)
            //{
            //    if (b.ImageNumber == 3)
            //        return true;
            //}
            //return false;
        }

        /// <summary>
        /// Get the index of the startbutton
        /// </summary>
        private int GetStart()
        {
            int i = 0;
            foreach(MapButton mb in _buttonList)
            {
                if(mb.ImageNumber == 0)
                {
                    return i;
                }
                i++;
            }
            return 999;
        }

        /// <summary>
        /// Get the index of the goalbutton
        /// </summary>
        private int GetGoal()
        {
            foreach(MapButton mb in _buttonList)
            {
                if(mb.ImageNumber == 3)
                {
                    return mb.Index;
                }
            }
            return 999;
        }

        /// <summary>
        /// Checks path and draws errors on conflict positions
        /// </summary>
        public void PathConflictCheck()
        {
            int index = 0;

            //runs trough map
            for(int y = 0; y < 18; y++)
            {
                for(int x = 0; x < 18; x++)
                {
                    // checks the starts
                    if(_buttonList.ElementAt(index).ImageNumber == 0)
                    {
                        DeactivateConflictedButtons(index, 1);
                    }
                    // checks the path
                    if(_buttonList.ElementAt(index).ImageNumber == 2)
                    {
                        DeactivateConflictedButtons(index, 2);
                    }
                    // checks the goal
                    if(_buttonList.ElementAt(index).ImageNumber == 3)
                    {
                        DeactivateConflictedButtons(index,1);
                    }
                    index++;
                }
            }
        }

        /// <summary>
        /// Go trough the the _map array and checks it
        /// </summary>
        /// <param name="map">The _map array which should be calculated</param>
        //public bool CheckWayConformity(int[,] map)
        //{
        //    var waypoints = new Queue<Vector2>();
        //    var currentPoint = new Vector2();

        //    for (int x = 0; x < map.GetLength(1); x++)
        //    {
        //        for (int y = 0; y < map.GetLength(0); y++)
        //        {
        //            int index = map[y, x];
        //            if (index == 0)
        //            {
        //                currentPoint.X = x;
        //                currentPoint.Y = y;

        //                Vector2 lastPoint = currentPoint;

        //                waypoints.Enqueue(currentPoint);

        //                while (map[(int)lastPoint.Y, (int)lastPoint.X] != 3)
        //                {
        //                    // Query: currentPoint +-1 in all directions = same Borders
        //                    if ((int)lastPoint.X - 1 >= 0) //left
        //                    {
        //                        if ((map[(int)lastPoint.Y, (int)lastPoint.X - 1] == 2 || map[(int)lastPoint.Y, (int)lastPoint.X - 1] == 3) && // point == way &&
        //                            !(waypoints.Contains(new Vector2(lastPoint.X - 1, lastPoint.Y)))) // Waypoint isn't in Queue
        //                        {
        //                            lastPoint.X = lastPoint.X - 1;
        //                            currentPoint = lastPoint;
        //                            waypoints.Enqueue(currentPoint);
        //                            continue;
        //                        }
        //                    }
        //                    if ((int)lastPoint.X + 1 < map.GetLength(0)) // right
        //                    {
        //                        if ((map[(int)lastPoint.Y, (int)lastPoint.X + 1] == 2 || map[(int)lastPoint.Y, (int)lastPoint.X + 1] == 3) &&
        //                            !(waypoints.Contains(new Vector2(lastPoint.X + 1, lastPoint.Y))))
        //                        {
        //                            lastPoint.X = lastPoint.X + 1;
        //                            currentPoint = lastPoint;
        //                            waypoints.Enqueue(currentPoint);
        //                            continue;
        //                        }
        //                    }
        //                    if ((int)lastPoint.Y - 1 >= 0) //up
        //                    {
        //                        if ((map[(int)lastPoint.Y - 1, (int)lastPoint.X] == 2 || map[(int)lastPoint.Y - 1, (int)lastPoint.X] == 3) &&
        //                            !(waypoints.Contains(new Vector2(lastPoint.X, lastPoint.Y - 1))))
        //                        {
        //                            lastPoint.Y = lastPoint.Y - 1;
        //                            currentPoint = lastPoint;
        //                            waypoints.Enqueue(currentPoint);
        //                            continue;
        //                        }
        //                    }
        //                    if ((int)lastPoint.Y + 1 < map.GetLength(0)) //down
        //                    {
        //                        if ((map[(int)lastPoint.Y + 1, (int)lastPoint.X] == 2 || map[(int)lastPoint.Y + 1, (int)lastPoint.X] == 3) &&
        //                            !(waypoints.Contains(new Vector2(lastPoint.X, lastPoint.Y + 1))))
        //                        {
        //                            lastPoint.Y = lastPoint.Y + 1;
        //                            currentPoint = lastPoint;
        //                            waypoints.Enqueue(currentPoint);
        //                            continue;
        //                        }
        //                    }
        //                }
        //                if (map[(int)lastPoint.Y, (int)lastPoint.X] == 3)
        //                {
        //                    return true;
        //                }
        //                break;
        //            }
        //        }
        //    }
        //    return false;
        //}

        /// <summary>
        /// Checks the Path and the conflicted Grass
        /// </summary>
        /// <param name="mb">The MapButton which should be changed</param>
        public void ActivateGrassConflictedButtons(MapButton mb)
        {
            if (mb.Index > 18)
            {
                if (_buttonList.ElementAt(mb.Index - 18).ImageNumber == 4)
                {
                    _buttonList.ElementAt(mb.Index - 18).Enabled = true;
                    _buttonList.ElementAt(mb.Index - 18).ImageNumber = 1;
                    _buttonList.ElementAt(mb.Index - 18).Image = Properties.Resources.grass_1;
                }
            }
            if (mb.Index > 1)
            {
                if (_buttonList.ElementAt(mb.Index - 1).ImageNumber == 4)
                {
                    _buttonList.ElementAt(mb.Index - 1).Enabled = true;
                    _buttonList.ElementAt(mb.Index - 1).ImageNumber = 1;
                    _buttonList.ElementAt(mb.Index - 1).Image = Properties.Resources.grass_1;
                }
            }
            if (mb.Index < 323)
            {
                if (_buttonList.ElementAt(mb.Index + 1).ImageNumber == 4)
                {
                    _buttonList.ElementAt(mb.Index + 1).Enabled = true;
                    _buttonList.ElementAt(mb.Index + 1).ImageNumber = 1;
                    _buttonList.ElementAt(mb.Index + 1).Image = Properties.Resources.grass_1;
                }
            }
            if (mb.Index < 305)
            {
                if (_buttonList.ElementAt(mb.Index + 18).ImageNumber == 4)
                {
                    _buttonList.ElementAt(mb.Index + 18).Enabled = true;
                    _buttonList.ElementAt(mb.Index + 18).ImageNumber = 1;
                    _buttonList.ElementAt(mb.Index + 18).Image = Properties.Resources.grass_1;
                }
            }
        }

        /// <summary>
        /// Deactivates the Buttons around the current Button
        /// </summary>
        /// <param name="index">The index of the current Button</param>
        /// <param name="counterborder">The number of allowed fields around 1 path</param>
        private void DeactivateConflictedButtons(int index, int counterborder)
        {
            int counter = 0;
            //north
            if(index >= 18 && (_buttonList.ElementAt(index - 18).ImageNumber == 0 ||
                _buttonList.ElementAt(index - 18).ImageNumber == 2 ||
                _buttonList.ElementAt(index - 18).ImageNumber == 3))
            {
                counter++;
            }

            //west
            if(index >= 1 && (_buttonList.ElementAt(index - 1).ImageNumber == 0 ||
                _buttonList.ElementAt(index - 1).ImageNumber == 2 ||
                _buttonList.ElementAt(index - 1).ImageNumber == 3))
            {
                counter++;
            }

            //east
            if(index < 323 && (_buttonList.ElementAt(index + 1).ImageNumber == 0 ||
                _buttonList.ElementAt(index + 1).ImageNumber == 2 ||
                _buttonList.ElementAt(index + 1).ImageNumber == 3))
            {
                counter++;
            }

            //south
            if(index <= 305 && (_buttonList.ElementAt(index + 18).ImageNumber == 0 ||
                _buttonList.ElementAt(index + 18).ImageNumber == 2 ||
                _buttonList.ElementAt(index + 18).ImageNumber == 3))
            {
                counter++;
            }
            //if more then 1 buttons around the actuall _button are filled it draws the forbidden fields
            if(counter >= counterborder)
            {
                if(index >= 18)
                {
                    if(_buttonList.ElementAt(index - 18).ImageNumber == 1)
                    {
                        _buttonList.ElementAt(index - 18).Enabled = false;
                        _buttonList.ElementAt(index - 18).ImageNumber = 4;
                    }
                }
                if(index <= 323)
                {
                    if(_buttonList.ElementAt(index + 1).ImageNumber == 1 && (((index + 1) % 18) != 0))
                    {
                        _buttonList.ElementAt(index + 1).Enabled = false;
                        _buttonList.ElementAt(index + 1).ImageNumber = 4;
                    }
                }
                if(index >= 1)
                {
                    if(_buttonList.ElementAt(index - 1).ImageNumber == 1 && (((index - 1) % 18) != 17))
                    {
                        _buttonList.ElementAt(index - 1).Enabled = false;
                        _buttonList.ElementAt(index - 1).ImageNumber = 4;
                    }
                }
                if(index <= 305)
                {
                    if(_buttonList.ElementAt(index + 18).ImageNumber == 1)
                    {
                        _buttonList.ElementAt(index + 18).Enabled = false;
                        _buttonList.ElementAt(index + 18).ImageNumber = 4;
                    }
                }
            }
        }

        /// <summary>
        /// Sets the image resources and tags of the buttons
        /// </summary>
        /// <param name="mapPoints">The map index array</param>
        /// <param name="index">The index variable</param>
        public void SetButtonImages(int[] mapPoints, int index)
        {
            for(int j = 0; j < index; j++)
            {
                switch(mapPoints[j])
                {
                    case 0:
                        _buttonList.ElementAt(j).Image = Properties.Resources.start_1;
                        _buttonList.ElementAt(j).ImageNumber = 0;
                        break;
                    case 1:
                        _buttonList.ElementAt(j).Image = Properties.Resources.grass_1;
                        _buttonList.ElementAt(j).ImageNumber = 1;
                        break;
                    case 2:
                        _buttonList.ElementAt(j).Image = Properties.Resources.path_1;
                        _buttonList.ElementAt(j).ImageNumber = 2;
                        break;
                    case 3:
                        _buttonList.ElementAt(j).Image = Properties.Resources.goal_1;
                        _buttonList.ElementAt(j).ImageNumber = 3;
                        break;
                    case 4:
                        _buttonList.ElementAt(j).Image = Properties.Resources.grass_1_disabled;
                        _buttonList.ElementAt(j).ImageNumber = 4;
                        break;
                    default:
                        _buttonList.ElementAt(j).Image = null;
                        _buttonList.ElementAt(j).ImageNumber = 1;
                        break;
                }
            }
        }

        #endregion

        #region events

        /// <summary>
        /// Changes the image property of the map buttons
        /// </summary>
        /// <param name="sender">The sender object</param>
        void ChangeDisabledButtonImages(object sender, EventArgs e)
        {
            var b = sender as Button;
            if (b != null)
                b.BackgroundImage = b.Enabled ? Properties.Resources.grass_1 : Properties.Resources.grass_1_disabled;
        }

        public void ButtonClick(object sender, EventArgs e)
        {
            //Changes the image resources of the sender buttons
            var senderButton = (MapButton)sender;

            switch(_currentTexture)
            {
                case "0":
                    senderButton.PreviousImageIndex = senderButton.ImageNumber;
                    senderButton.Image = Properties.Resources.start_1;
                    senderButton.ImageNumber = 0;
                    break;
                case "1":
                    senderButton.PreviousImageIndex = senderButton.ImageNumber;
                    senderButton.Image = Properties.Resources.grass_1;
                    senderButton.ImageNumber = 1;
                    break;
                case "2":
                    senderButton.PreviousImageIndex = senderButton.ImageNumber;
                    senderButton.Image = Properties.Resources.path_1;
                    senderButton.ImageNumber = 2;
                    break;
                case "3":
                    senderButton.PreviousImageIndex = senderButton.ImageNumber;
                    senderButton.Image = Properties.Resources.goal_1;
                    senderButton.ImageNumber = 3;
                    break;
                case "":
                    senderButton.PreviousImageIndex = senderButton.ImageNumber;
                    senderButton.Image = null;
                    senderButton.ImageNumber = 1;
                    break;
            }

            if (senderButton.ImageNumber == 1)
            {
                ActivateGrassConflictedButtons(senderButton);
            }

            PathConflictCheck();

            //Changes the status of the waybuttons
            _editor.EnableDisableButtons((int)_buttonList.ElementAt<MapButton>(senderButton.Index).ImageNumber);
        }

        #endregion
    }
}
